home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: gdevstc2.c,v 1.2 2000/09/19 19:00:22 lpd Exp $*/
- /* Epson Stylus-Color Printer-Driver */
-
- /***
- This file holds two implementations of the Floyd-Steinberg error
- diffusion-algorithm. This algorithms are intended for high quality
- printing in conjunction with the PostScript-Header stcolor.ps:
-
- gs -sDEVICE=stcolor <other options> stcolor.ps ...
-
- Most prominent option is -sDithering=xxx, to select the algorithm:
-
- fsmono - monochrome Floyd-Steinberg
- fsrgb - 3-Component Floyd-Steinberg
- fsx4 - 4-Component Floyd-Steinberg (Bad results)
-
- fscmyk - Modified 4-Component Floyd-Steinberg
- (Algorithmically identical with hscmyk, but slower)
-
- ***/
-
- #include "gdevstc.h"
-
- #include <stdlib.h> /* for rand */
-
- /*
- Both algorithms require an error-buffer of
-
- 3 + 3*num_components +1*scan long-items.
-
- and must consequently set up to work with longs.
- It is just a Floyd-Steinberg-algorithm applied to each component.
-
- */
-
- /*
- * Due to the -selfdefined- ugly coding of the output-data, we need
- * some conversion. But since this includes the black-separation, I
- * did not change the definition.
- *
- * This algorithm stores the 1st component in the LSB, thus it
- * reverts the order used by the basic driver.
- */
-
- static const byte grayvals[2] = { 0, BLACK };
-
- static const byte rgbvals[8] = {
- 0, RED, GREEN, RED|GREEN, BLUE, BLUE|RED, BLUE|GREEN, BLUE|RED|GREEN};
-
- static const byte cmykvals[16] = {
- 0, CYAN,MAGENTA,CYAN|MAGENTA,YELLOW,YELLOW|CYAN,YELLOW|MAGENTA,BLACK,
- BLACK,BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,BLACK};
-
- static const byte *const pixelconversion[5] = {
- NULL, grayvals, NULL, rgbvals, cmykvals};
-
-
- int
- stc_fs(stcolor_device *sdev,int npixel,byte *bin,byte *bbuf,byte *out)
- {
-
- long *in = (long *) bin;
- long *buf = (long *) bbuf;
-
- /* ============================================================= */
- if(npixel > 0) { /* npixel > 0 -> scanline-processing */
- /* ============================================================= */
-
- int bstep,pstart,pstop,pstep,p;
- long spotsize,threshold,*errc,*errv;
- const byte *pixel2stc;
-
- if(buf[0] >= 0) { /* run forward */
- buf[0] = -1;
- bstep = 1;
- pstep = sdev->color_info.num_components;
- pstart = 0;
- pstop = npixel * pstep;
-
- } else { /* run backward */
- buf[0] = 1;
- bstep = -1;
- pstep = -sdev->color_info.num_components;
- pstop = pstep;
- pstart = (1-npixel) * pstep;
- out += npixel-1;
- } /* forward / backward */
-
- /* --------------------------------------------------------------------- */
- if(in == NULL) return 0; /* almost ignore the 'white calls' */
- /* --------------------------------------------------------------------- */
-
- spotsize = buf[1];
- threshold = buf[2];
- errc = buf+3;
- errv = errc + 2*sdev->color_info.num_components;
- pixel2stc = pixelconversion[sdev->color_info.num_components];
-
- for(p = pstart; p != pstop; p += pstep) { /* loop over pixels */
- int c; /* component-number */
- int pixel; /* internal pxel-value */
-
- pixel = 0;
-
- for(c = 0; c < sdev->color_info.num_components; c++) { /* comp */
- long cv; /* component value */
-
- cv = in[p+c] + errv[p+c] + errc[c] - ((errc[c]+4)>>3);
- if(cv > threshold) {
- pixel |= 1<<c;
- cv -= spotsize;
- }
- errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
- errv[p+c ] = ((5*cv )>>4) /* 5/16 */
- + ((errc[c]+4)>>3); /* 1/16 (rest) */
- errc[c] = cv /* 8/16 (neu) */
- - ((5*cv )>>4)
- - ((3*cv+8)>>4);
- } /* comp */
-
- *out = pixel2stc[pixel];
- out += bstep;
- } /* loop over pixels */
-
-
- /* ============================================================= */
- } else { /* npixel <= 0 -> initialisation */
- /* ============================================================= */
-
- int i,i2do;
- long rand_max;
- double offset,scale;
-
- /*
- * check wether the number of components is valid
- */
- if((sdev->color_info.num_components < 0) ||
- (sdev->color_info.num_components >= countof(pixelconversion)) ||
- (pixelconversion[sdev->color_info.num_components] == NULL)) return -1;
-
- /*
- * check wether stcdither & TYPE are correct
- */
- if(( sdev->stc.dither == NULL) ||
- ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2;
-
- /*
- * check wether the buffer-size is sufficiently large
- */
- if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
- ( sdev->stc.dither->bufadd <
- (3 + 3*sdev->color_info.num_components))) return -3;
- /*
- * must neither have STC_DIRECT nor STC_WHITE
- */
- if(sdev->stc.dither->flags & (STC_DIRECT | STC_WHITE)) return -4;
-
- /*
- * compute initial values
- */
- /* -- direction */
- buf[0] = 1;
-
- /* -- "spotsize" */
- scale = sdev->stc.dither->minmax[1];
- buf[1] = scale + (scale > 0.0 ? 0.5 : -0.5);
-
- /* -- "threshold" */
- offset = sdev->stc.dither->minmax[0];
- scale -= offset;
- if((offset+0.5*scale) > 0.0) buf[2] = offset + 0.5*scale + 0.5;
- else buf[2] = offset + 0.5*scale - 0.5;
-
- /*
- * random values, that do not exceed half of normal value
- */
- i2do = sdev->color_info.num_components * (3-npixel);
- rand_max = 0;
-
- if(sdev->stc.flags & STCDFLAG0) {
-
- for(i = 0; i < i2do; ++i) buf[i+3] = 0;
-
- } else {
-
- for(i = 0; i < i2do; ++i) {
- buf[i+3] = rand();
- if(buf[i+3] > rand_max) rand_max = buf[i+3];
- }
-
- scale = (double) buf[1] / (double) rand_max;
-
- for(i = 0; i < sdev->color_info.num_components; ++ i)
- buf[i+3] = 0.25000*scale*(buf[i+3]-rand_max/2);
-
- for( ; i < i2do; ++i) /* includes 2 additional pixels ! */
- buf[i+3] = 0.28125*scale*(buf[i+3]-rand_max/2);
-
- }
-
- /* ============================================================= */
- } /* scanline-processing or initialisation */
- /* ============================================================= */
-
- return 0;
- }
-
- /*
- * Experimental CMYK-Algorithm
- */
-
- int
- stc_fscmyk(stcolor_device *sdev,int npixel,byte *bin,byte *bbuf,byte *out)
- {
- long *in = (long *) bin;
- long *buf = (long *) bbuf;
-
- /* ============================================================= */
- if(npixel > 0) { /* npixel > 0 -> scanline-processing */
- /* ============================================================= */
-
- int bstep,pstart,pstop,pstep,p;
- long spotsize,threshold,*errc,*errv;
-
- if(buf[0] >= 0) { /* run forward */
- buf[0] = -1;
- bstep = 1;
- pstep = 4;
- pstart = 0;
- pstop = npixel * pstep;
-
- } else { /* run backward */
- buf[0] = 1;
- bstep = -1;
- pstep = -4;
- pstop = pstep;
- pstart = (1-npixel) * pstep;
- out += npixel-1;
- } /* forward / backward */
-
- spotsize = buf[1];
- threshold = buf[2];
- errc = buf+3;
- errv = errc + 2*4;
-
- for(p = 0; p < 4; ++p) errc[p] = 0;
-
- for(p = pstart; p != pstop; p += pstep) { /* loop over pixels */
- int c; /* component-number */
- int pixel; /* internal pxel-value */
- long cv,k;
-
- /*
- * Black is treated first, with conventional Floyd-Steinberg
- */
- k = in[p+3];
- cv = k + errv[p+3] + errc[3] - ((errc[3]+4)>>3);
-
- if(cv > threshold) {
- pixel = BLACK;
- cv -= spotsize;
- } else {
- pixel = 0;
- }
-
- errv[p+3-pstep] += ((3*cv+8)>>4); /* 3/16 */
- errv[p+3 ] = ((5*cv )>>4) /* 5/16 */
- + ((errc[3]+4)>>3); /* 1/16 (rest) */
- errc[3] = cv /* 8/16 (neu) */
- - ((5*cv )>>4)
- - ((3*cv+8)>>4);
-
- /*
- * color-handling changes with black fired or not
- */
- if(pixel) {
-
- /* -------- firing of black causes all colors to fire too */
-
- for(c = 0; c < 3; ++c) {
- cv = in[p+c] > k ? in[p+c] : k;
- cv += errv[p+c] + errc[c] - ((errc[c]+4)>>3)-spotsize;
- if(cv <= (threshold-spotsize)) cv = threshold-spotsize+1;
-
- errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
- errv[p+c ] = ((5*cv )>>4) /* 5/16 */
- + ((errc[c]+4)>>3); /* 1/16 (rest) */
- errc[c] = cv /* 8/16 (neu) */
- - ((5*cv )>>4)
- - ((3*cv+8)>>4);
- }
-
- } else {
-
- /* -------- if black did not fire, only colors w. larger values may fire */
-
- for(c = 0; c < 3; ++c) {
-
- cv = in[p+c];
-
- if(cv > k) { /* May Fire */
- cv += errv[p+c] + errc[c] - ((errc[c]+4)>>3);
- if(cv > threshold) {
- cv -= spotsize;
- pixel |= CYAN>>c;
- }
- } else { /* Must not fire */
- cv = k + errv[p+c] + errc[c] - ((errc[c]+4)>>3);
- if(cv > threshold ) cv = threshold;
- }
-
- errv[p+c-pstep] += ((3*cv+8)>>4); /* 3/16 */
- errv[p+c ] = ((5*cv )>>4) /* 5/16 */
- + ((errc[c]+4)>>3); /* 1/16 (rest) */
- errc[c] = cv /* 8/16 (neu) */
- - ((5*cv )>>4)
- - ((3*cv+8)>>4);
- }
- }
-
- *out = pixel;
- out += bstep;
- } /* loop over pixels */
-
-
- /* ============================================================= */
- } else { /* npixel <= 0 -> initialisation */
- /* ============================================================= */
-
- int i,i2do;
- long rand_max;
- double offset,scale;
-
- /*
- * check wether the number of components is valid
- */
- if(sdev->color_info.num_components != 4) return -1;
-
- /*
- * check wether stcdither & TYPE are correct
- */
- if(( sdev->stc.dither == NULL) ||
- ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2;
-
- /*
- * check wether the buffer-size is sufficiently large
- */
- if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
- ( sdev->stc.dither->bufadd <
- (3 + 3*sdev->color_info.num_components))) return -3;
- /*
- * must neither have STC_DIRECT nor STC_WHITE
- */
- if(sdev->stc.dither->flags & (STC_DIRECT | STC_WHITE)) return -4;
-
- /*
- * compute initial values
- */
- /* -- direction */
- buf[0] = 1;
-
- /* -- "spotsize" */
- scale = sdev->stc.dither->minmax[1];
- buf[1] = scale + (scale > 0.0 ? 0.5 : -0.5);
-
- /* -- "threshold" */
- offset = sdev->stc.dither->minmax[0];
- scale -= offset;
- if(sdev->stc.flags & STCDFLAG1) {
- buf[2] = (sdev->stc.extv[0][sdev->stc.sizv[0]-1] - sdev->stc.extv[0][0])
- * scale / 2.0 + offset;
- } else {
- if((offset+0.5*scale) > 0.0) buf[2] = offset + 0.5*scale + 0.5;
- else buf[2] = offset + 0.5*scale - 0.5;
- }
-
- /*
- * random values, that do not exceed half of normal value
- */
- i2do = sdev->color_info.num_components * (3-npixel);
- rand_max = 0;
-
- if(sdev->stc.flags & STCDFLAG0) {
-
- for(i = 0; i < i2do; ++i) buf[i+3] = 0;
-
- } else {
-
- for(i = 0; i < i2do; ++i) {
- buf[i+3] = rand();
- if(buf[i+3] > rand_max) rand_max = buf[i+3];
- }
-
- scale = (double) buf[1] / (double) rand_max;
-
- for(i = 0; i < sdev->color_info.num_components; ++ i)
- buf[i+3] = 0.25000*scale*(buf[i+3]-rand_max/2);
-
- for( ; i < i2do; ++i) /* includes 2 additional pixels ! */
- buf[i+3] = 0.28125*scale*(buf[i+3]-rand_max/2);
-
- }
-
- /* ============================================================= */
- } /* scanline-processing or initialisation */
- /* ============================================================= */
-
- return 0;
- }
-